package com.wmx.thymeleafapp.listeners;

import cn.hutool.core.thread.ThreadUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Random;

/**
 * Redis 消息订阅-消息监听器，当收到阅订的消息时，会将消息交给这个类处理
 * <p>
 * 1、可以直接实现 MessageListener 接口，也可以继承它的实现类 MessageListenerAdapter.
 * 2、自动多线程处理，打印日志即可看出，即使手动延迟，也不会影响后面消息的接收。
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2022/5/21 16:00
 */
@Component
public class RedisSubListener implements MessageListener {

    private static final Logger log = LoggerFactory.getLogger(RedisSubListener.class);

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 监听到的消息必须进行与发送时相同的方式进行反序列
     * 1、订阅端与发布端 Redis 序列化的方式必须相同，否则会乱码。
     *
     * @param message ：消息实体
     * @param pattern ：匹配模式
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 消息订阅的匹配规则，如 new PatternTopic("basic-*") 中的 basic-*
        String msgPattern = new String(pattern);
        // 消息所属的通道，可以根据不同的通道做不同的业务逻辑
        String channel = (String) redisTemplate.getStringSerializer().deserialize(message.getChannel());
        // 接收的消息内容，可以根据自己需要强转为自己需要的对象，但最好先使用 instanceof 判断一下
        Object body = redisTemplate.getValueSerializer().deserialize(message.getBody());

        // 收到 Redis 订阅消息: channel=basic-service body=flushDb pattern=basic-*
        // 收到 Redis 订阅消息: channel=memoryCache body=flushAll pattern=memoryCache
        log.info("收到 Redis 订阅消息: channel={} body={} pattern={} ", channel, body, msgPattern);

        // 手动延迟，模拟数据处理
        ThreadUtil.safeSleep(800 + new Random().nextInt(3000));
        log.info("------------数据处理完成.......");
    }

}